package com.learning.optimize.jdk.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;

/**
 * ClassName: ConstructorReflect
 * Description: Constructor 类以及构造函数反射
 * Date: 2018/7/17 22:42 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class ConstructorReflect {

    public static void main(String[] args) throws Exception {
        test();
//        test1();
//        test2();
    }

    /**
     * @throws Exception
     */
    static void test() throws Exception {

        // 获取Class对象的引用
        Class<?> clazz = Class.forName("com.learning.optimize.jdk.reflect.User");

        // 获取带 String 参数的 public 构造函数
        Constructor cs1 = clazz.getConstructor(String.class);
        System.out.println(cs1.toGenericString());
        System.out.println("--------------------------------------------");

        // 取得指定带 int 和 String 参数构造函数, 该方法是私有构造 private
        Constructor cs2 = clazz.getDeclaredConstructor(int.class, String.class);
        System.out.println(cs2.toGenericString());
        System.out.println("--------------------------------------------");

        // 获取所有的构造，不包括 private
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.toGenericString());
        }
        System.out.println("--------------------------------------------");

        // 获取所有构造包含 private
        Constructor<?> cons[] = clazz.getDeclaredConstructors();
        // 查看每个构造方法需要的参数
        for (int i = 0; i < cons.length; i++) {
            //获取构造函数参数类型
            Class<?>[] clazzs = cons[i].getParameterTypes();
            System.out.println("构造函数[" + i + "]:" + cons[i].toString());
            System.out.print("参数类型[" + i + "]:(");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1) {
                    System.out.print(clazzs[j].getName());
                } else {
                    System.out.print(clazzs[j].getName() + ",");
                }
            }
            System.out.println(")");
        }


        /*
        *
        public com.learning.optimize.jdk.reflect.User(java.lang.String)
        --------------------------------------------
        private com.learning.optimize.jdk.reflect.User(int,java.lang.String)
        --------------------------------------------
        public com.learning.optimize.jdk.reflect.User(java.lang.String)
        public com.learning.optimize.jdk.reflect.User()
        --------------------------------------------
        构造函数[0]:private com.learning.optimize.jdk.reflect.User(int,java.lang.String)
        参数类型[0]:(int,java.lang.String)
        构造函数[1]:public com.learning.optimize.jdk.reflect.User(java.lang.String)
        参数类型[1]:(java.lang.String)
        构造函数[2]:public com.learning.optimize.jdk.reflect.User()
        参数类型[2]:()
        * */
    }

    /**
     * Constructor-API
     *
     * @throws Exception
     */
    static void test1() throws Exception {
        // 获取Class对象的引用
        Class<?> clazz = Class.forName("com.learning.optimize.jdk.reflect.User");
        Constructor cs = clazz.getDeclaredConstructor(int.class, String.class);

        System.out.println("-----getDeclaringClass-----");
        Class uclazz = cs.getDeclaringClass();
        // Constructor对象表示的构造方法的类
        System.out.println("构造方法的类:" + uclazz.getName());

        System.out.println("-----getGenericParameterTypes-----");
        // 对象表示此 Constructor 对象所表示的方法的形参类型
        Type[] tps = cs.getGenericParameterTypes();
        for (Type tp : tps) {
            System.out.println("参数名称tp:" + tp);
        }
        System.out.println("-----getParameterTypes-----");
        // 获取构造函数参数类型
        Class<?> clazzs[] = cs.getParameterTypes();
        for (Class claz : clazzs) {
            System.out.println("参数名称:" + claz.getName());
        }
        System.out.println("-----getName-----");
        // 以字符串形式返回此构造方法的名称
        System.out.println("getName:" + cs.getName());

        System.out.println("-----toGenericString-----");
        // 返回描述此 Constructor 的字符串，其中包括类型参数。
        System.out.println("toGenericString():" + cs.toGenericString());

        /*
        *   -----getDeclaringClass-----
            构造方法的类:com.learning.optimize.jdk.reflect.User
            -----getGenericParameterTypes-----
            参数名称tp:int
            参数名称tp:class java.lang.String
            -----getParameterTypes-----
            参数名称:int
            参数名称:java.lang.String
            -----getName-----
            getName:com.learning.optimize.jdk.reflect.User
            -----toGenericString-----
            toGenericString():private com.learning.optimize.jdk.reflect.User(int,java.lang.String)
        * */
    }

    /**
     * 利用Constructor 实例化对象
     */
    static void test2() throws Exception {

        // 获取Class对象的引用
        Class<?> clazz = Class.forName("com.learning.optimize.jdk.reflect.User");

        // 第一种方法，实例化默认构造方法，User必须有无参构造函数，否则将抛异常
        User user = (User) clazz.newInstance();
        user.setAge(20);
        user.setName("Sam");
        System.out.println(user);

        System.out.println("--------------------------------------------");

        // 获取带 String 参数的 public 构造函数
        Constructor cs1 = clazz.getConstructor(String.class);
        //创建User
        User user1 = (User) cs1.newInstance("Rabby");
        user1.setAge(22);
        System.out.println("user1:" + user1.toString());

        System.out.println("--------------------------------------------");

        // 取得指定带 int 和 String 参数构造函数, 该方法是私有构造 private
        Constructor cs2 = clazz.getDeclaredConstructor(int.class, String.class);
        //由于是 private 必须设置可访问
        cs2.setAccessible(true);
        //创建user对象
        User user2 = (User) cs2.newInstance(25, "Eason");
        System.out.println("user2:" + user2.toString());

        System.out.println("--------------------------------------------");

        /*
        *   com.learning.optimize.jdk.reflect.User@5cad8086
            --------------------------------------------
            user1:com.learning.optimize.jdk.reflect.User@6e0be858
            --------------------------------------------
            user2:com.learning.optimize.jdk.reflect.User@61bbe9ba
            --------------------------------------------
        * */
    }
}

class User {
    private int age;
    private String name;

    public User() {
        super();
    }

    public User(String name) {
        super();
        this.name = name;
    }

    /**
     * 私有构造
     *
     * @param age
     * @param name
     */
    private User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
